﻿using Nemerle;
using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;

using System;
using System.IO;
using System.Diagnostics;
using System.Reflection;
using System.Collections;
using System.Resources;
using System.Collections.Generic;
using System.Linq;

using Nitra;
using Nitra.Declarations;
using Nitra.ProjectSystem;

using Ammy.Infrastructure;
using Ammy.Resource;

namespace Ammy
{
  /*
  class ResourceLoader
  {
    static NoFile : ProjectSystem.File = SourceSnapshot.Default.File;
    static NoSpan : NSpan = NSpan(0);
    
    _dictionaryType : System.Type;
    _dictionarySourceProperty : PropertyInfo;
    public this() 
    {
      _dictionaryType = ReflectionTypeProvider.FindType("System.Windows.ResourceDictionary");    
      _dictionarySourceProperty = _dictionaryType.GetProperty("Source", BindingFlags.Public | BindingFlags.Instance);
    }
    
    public GetResourceDictionaryScope(project : Project) : TableScope
    {
      def dictionaryScope = TableScope("", null);
      
      foreach(lib in project.Libs) {
        try { 
          LoadResourceDictionariesFromLibReference(project, lib, dictionaryScope) 
        } 
        catch { 
          | _ => () 
        }
      }

      dictionaryScope
    }
    private LoadResourceDictionariesFromLibReference(project : Project, lib : LibReference, dictionaryScope : TableScope) : void
    {
      def path = match (lib) {
        | x is FullNameLibReference => x.Path
        | x is FileLibReference => x.Path
        | x is ProjectReference => Path.Combine(project.ProjectDir, x.RelativePath)
        | _ => throw Exception("Unsupported lib reference " + lib.ToString())
      };
      def assembly = Assembly.LoadFile(path);     
      def assemblyName = assembly.FullName.Split(',')[0];
      def resourcesNames = assembly.GetManifestResourceNames();

      mutable container : ResourceContainerSymbol; 

      def uris = resourcesNames.Where(name => assembly.GetManifestResourceInfo(name).ResourceLocation != ResourceLocation.ContainedInAnotherAssembly)
                               .SelectMany(name => GetResourceDictionaries(assembly, name))
                               .Select(name => Uri($"pack://application:,,,/$(assemblyName);component/$(name)", UriKind.Absolute));
      
      foreach (uri in uris) {
        try { 
          def dictionary = Activator.CreateInstance(_dictionaryType);
          _dictionarySourceProperty.SetValue(dictionary, uri);
          
          container = container ?? {
            def c = ExternalDeclaration.[ResourceContainerSymbol](Name(Location(SourceSnapshot.Default.File, NSpan(0)), assemblyName)).DefineSymbol(dictionaryScope);
            c.MemberTable = TableScope(uri.AbsoluteUri, null);
            c
          };
          
          //def resources = GetResourcesFromDictionary(dictionary);
          //              
          //foreach ((key, value) in resources) {
          //  def symbol = ExternalDeclaration.[ResourceSymbol](Name(NoFile, NoSpan, key)).DefineSymbol(container.MemberTable);
          //  symbol.FullName = key;
          //  symbol.Value = value;
          //  symbol.Parent = container;
          //  symbol.Dictionary = dictionary;
          //}
          
    
        } catch {
          | _ => ()
        }
      }
    }
    
    public _GetResourcesFromDictionary(dictionary : object) : List[(string * object)] 
    {
      def resources = List();
        
      def items = dictionary :> ICollection;                  
      foreach (item is DictionaryEntry in items)
        resources.Add((item.Key.ToString(), item.Value));
      
      resources
    }
    
    private GetEntryName(entry : DictionaryEntry) : option[string] {
      def key = entry.Key.ToString();
      if (key.EndsWith(".baml")) Some(Path.ChangeExtension(key, ".xaml"));
      else if (key.EndsWith(".xaml")) Some(key);
      else None();
    }
    
    private GetResourceDictionaries(assembly : Assembly, resourceName : string) : IEnumerable[string] 
    {
      //def container = 
      def resourceStream = assembly.GetManifestResourceStream(resourceName);
      using (reader = ResourceReader(resourceStream))
        foreach (entry is DictionaryEntry in reader) {
          def name = GetEntryName(entry);
          when (name is Some(x))
            yield x;
        }
    }
  }
  */
}
